package com.micro.service.gateway.web.filter;

import com.micro.service.common.constants.LoginConstant;
import com.micro.service.gateway.config.ParameterRequestWrapper;
import com.micro.service.gateway.util.CookieTool;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestOperations;
import org.springframework.web.client.RestTemplate;

import javax.servlet.*;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;

/**
 * 通用拦截  编码处理  log 处理
 * */
@Component
@Slf4j
public class CommonFilter implements Filter{

    private RestOperations restTemplate = new RestTemplate();

    @Value("${security.oauth2.resource.token-info-uri}")
    private String checkTokenEndpointUrl;
    @Value("server.contextPath")
    private String contextPath;

    @Override
    public void destroy() {

    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Assert.notNull(checkTokenEndpointUrl,"checkTokenEndpointUrl不能为空！");
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        
        HttpServletResponse response = (HttpServletResponse) resp;

        encodeFilter(request, response, chain);

    }

    private void encodeFilter(HttpServletRequest req, HttpServletResponse resp, FilterChain chain) throws IOException, ServletException {
//        if (log.isInfoEnabled()) {
//            log.info("CommonFilter.encodeFilter过滤所有请求并设置编码为UTF-8,请求 requestURI: {}",req.getRequestURI());
//        }
        req.setCharacterEncoding("UTF-8");
        resp.setCharacterEncoding("UTF-8");

        req.setAttribute("contextPath",contextPath);
        
        //判断 juuid 写入cookie值
        Cookie cookie = CookieTool.getCookieByName(req, "juuid");
        if (cookie == null) {
            cookie = new Cookie("juuid", CookieTool.getOrSetUserSessionId(req, resp));
            resp.addCookie(cookie);
            resp.setHeader("Cache-Control", "no-cache"); // HTTP 1.1
            resp.setHeader("Pragma", "no-cache"); // HTTP 1.0
        }

        String uri = req.getRequestURI();
        ParameterRequestWrapper parameterRequestWrapper = new ParameterRequestWrapper(req);
        String accessToken = req.getHeader("token");

        //需要tonken强制校验的URL处理
        for(String needLoginUrl: LoginConstant.NEED_LOGIN_URLS){
            if(uri != null && uri.contains(needLoginUrl)){
                if(!isTokenValid(accessToken)){//验证失败直接返回异常
                    throw new InvalidTokenException("无效的身份令牌");
                }else{
                    parameterRequestWrapper.addParameter("access_token",accessToken);
                }
                break;
            }
        }


        chain.doFilter(parameterRequestWrapper, resp);
    }

    private boolean isTokenValid(String accessToken){
        MultiValueMap<String, String> formData = new LinkedMultiValueMap();
        formData.add("token", accessToken);
        HttpHeaders headers = new HttpHeaders();
        Map<String, Object> map = this.postForMap(this.checkTokenEndpointUrl, formData, headers);

        return map != null && map.containsKey("active") && "true".equals(String.valueOf(map.get("active")));
    }

    private Map<String, Object> postForMap(String path, MultiValueMap<String, String> formData, HttpHeaders headers) {
        if (headers.getContentType() == null) {
            headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        }

        Map map = (Map)this.restTemplate.exchange(path, HttpMethod.POST, new HttpEntity(formData, headers), Map.class, new Object[0]).getBody();
        return map;
    }

}
